﻿#region File Description
/*-----------------------------------------------------------------------------
 Author: Jose Antonio Gallego
 Date: 24/10/2011
 
 License: Ms-PL
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

 The example companies, organizations, products, domain names,
 e-mail addresses, logos, people, places, and events depicted
 herein are fictitious.  No association with any real company,
 organization, product, domain name, email address, logo, person,
 places, or events is intended or should be inferred.
-----------------------------------------------------------------------------*/
#endregion


#region Using Statements
using System;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Windows;
#endregion

namespace Zombsquare.Helpers
{
    /// <summary>
    /// Clase para la gestión del almacenamiento y serialización de contenidos
    /// </summary>
    public class Storage
    {
        private static Object _thisLock = new Object();

        /// <summary>
        /// Carga un objeto serializado en el almacen
        /// </summary>
        /// <typeparam name="T">Tipo del objeto a recuperar</typeparam>
        /// <param name="fileName">Nombre del archivo</param>
        /// <returns>retorna el objeto</returns>
        public static T LoadSetting<T>(string fileName)
        {


            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!store.FileExists(fileName))
                {
                    return default(T);
                }

                lock (_thisLock)
                {
                    try
                    {
                        using (var stream = store.OpenFile(fileName, FileMode.Open, FileAccess.Read))
                        {
                            var serializer = new DataContractSerializer(typeof(T));                            
                            return (T)serializer.ReadObject(stream);
                        }
                    }
                    catch (SerializationException se)
                    {                        
                        DeleteFile(fileName);
                        return default(T);                        
                    }
                    catch (Exception e)
                    {                     
                        DeleteFile(fileName);
                        return default(T);
                    }
                }
            }
        }

        /// <summary>
        /// Guarda un objeto serializado en el almacen
        /// </summary>
        /// <typeparam name="T">Tipo del objeto</typeparam>
        /// <param name="fileName">Nombre del archivo</param>
        /// <param name="dataToSave">Objeto a guardar</param>
        public static void SaveSetting<T>(string fileName, T dataToSave)
        {
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                lock (_thisLock)
                {
                    try
                    {
                        using (var stream = store.CreateFile(fileName))
                        {
                            var serializer = new DataContractSerializer(typeof(T));
                            serializer.WriteObject(stream, dataToSave);
                        }
                    }
                    catch (Exception e)
                    {
                        DeleteFile(fileName);
                        return;
                    }
                }
            }
        }

        public static Stream StreamFileFromIsoStore(string filename)
        {
            var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
            using (isoStore)
            {
                return isoStore.OpenFile(filename, FileMode.Open);
            }
        }

        public static bool FileExists(string filename)
        {
            var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
            using (isoStore)
            {
                return isoStore.FileExists(filename);
            }
        }

        public static void DeleteFile(string filename)
        {
            var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
            try
            {
                isoStore.DeleteFile(filename);
            }
            catch
            {
            }
        }

        public static string GetFileAsString(string filename)
        {
            var filestream = StreamFileFromIsoStore(filename);

            var s = new StreamReader(filestream);
            return s.ReadToEnd();
        }

        public static void CreateDirectoryStructure(string fileName)
        {
            var strBaseDir = string.Empty;
            var delimStr = "/";
            var delimiter = delimStr.ToCharArray();
            var dirsPath = fileName.Split(delimiter);

            //Get the IsoStore
            var isoStore = IsolatedStorageFile.GetUserStoreForApplication();

            //Recreate the directory structure
            for (int i = 0; i < dirsPath.Length - 1; i++)
            {
                strBaseDir = System.IO.Path.Combine(strBaseDir, dirsPath[i]);
                if (!isoStore.DirectoryExists(strBaseDir))
                    isoStore.CreateDirectory(strBaseDir);
            }
        }

        public static void SaveToIsoStore(string fileName, Stream stream)
        {
            byte[] data = ReadFully(stream, (int)stream.Length);
            stream.Close();

            SaveToIsoStore(fileName, data);
        }

        public static void SaveToIsoStore(string fileName, byte[] data)
        {
            CreateDirectoryStructure(fileName);
            //Get the IsoStore
            var isoStore = IsolatedStorageFile.GetUserStoreForApplication();

            //Write the file
            using (var bw = new BinaryWriter(isoStore.CreateFile(fileName)))
            {
                bw.Write(data);
                bw.Close();
            }
        }

        /// <summary>
        /// Reads data from a stream until the end is reached. The
        /// data is returned as a byte array. An IOException is
        /// thrown if any of the underlying IO calls fail.
        /// </summary>
        /// <param name="stream">The stream to read data from</param>
        /// <param name="initialLength">The initial buffer length</param>
        public static byte[] ReadFully(Stream stream, int initialLength)
        {

            if (initialLength < 1)
            {
                initialLength = 32768;
            }

            byte[] buffer = new byte[initialLength];
            int read = 0;

            int chunk;
            while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
            {
                read += chunk;

                // If we've reached the end of our buffer, check to see if there's
                // any more information
                if (read == buffer.Length)
                {
                    int nextByte = stream.ReadByte();

                    // End of stream? If so, we're done
                    if (nextByte == -1)
                    {
                        return buffer;
                    }

                    // Nope. Resize the buffer, put in the byte we've just
                    // read, and continue
                    byte[] newBuffer = new byte[buffer.Length * 2];
                    Array.Copy(buffer, newBuffer, buffer.Length);
                    newBuffer[read] = (byte)nextByte;
                    buffer = newBuffer;
                    read++;
                }
            }
            // Buffer is now too big. Shrink it.
            byte[] ret = new byte[read];
            Array.Copy(buffer, ret, read);
            return ret;
        }

        private static IsolatedStorageFile isf;

        public static void CopyFileToSotrage(string fileName, string name)
        {
            isf = IsolatedStorageFile.GetUserStoreForApplication();

            if (!isf.FileExists(name))
            {
                CopyFromContentToStorage(fileName,name);
            }
        }

        private static void CopyFromContentToStorage(String dbName, string fileName)
        {

            IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();

            System.IO.Stream src = Application.GetResourceStream(
                 new Uri(@"/Zombsquare;component/" + dbName, UriKind.Relative)).Stream;

            IsolatedStorageFileStream dest = new IsolatedStorageFileStream(
                fileName,
                System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write,
                store);

            src.Position = 0;
            CopyStream(src, dest);
            dest.Flush();
            dest.Close();
            src.Close();
            dest.Dispose();
        }

        private static void CopyStream(System.IO.Stream input, IsolatedStorageFileStream output)
        {
            byte[] buffer = new byte[32768];
            long TempPos = input.Position;
            int readCount;

            do
            {
                readCount = input.Read(buffer, 0, buffer.Length);
                if (readCount > 0)
                {
                    output.Write(buffer, 0, readCount);
                }

            } while (readCount > 0);
            input.Position = TempPos;
        }

    }
}
